package com.ai.networking.netty.client;


import com.ai.entity.network.HeartMessage;
import com.ai.networking.netty.comm.CommonNetty;
import com.ai.entity.comm.SysNetty;
import com.ai.networking.netty.service.SendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 客户端与服务端的心跳
 */
@Slf4j
@Component
public class BootNettyHeartTimer {

    // 定义一个Map，用于存储每个客户端的失败重连次数
    private static final Map<String, Integer> reconnectAttempts = new HashMap<>();

    // 定义一个Map，用于存储每个客户端的最后重连时间
    private static final Map<String, Long> lastReconnectTime = new HashMap<>();

    // 定义最大重连间隔时间，单位为秒
    private static final int MAX_RECONNECT_DELAY = 60;  // 最大60秒重连

    @Scheduled(fixedRate = 2000 *30)  // 每2秒执行一次心跳检查
    public void heart_timer() {
        // 所有已经连接的客户端
        if (CommonNetty.NATIVE_CLIENT_MAP.size() > 0) {
            for (Map.Entry<String, SysNetty> entry : CommonNetty.NATIVE_CLIENT_MAP.entrySet()) {
                String code = entry.getKey();
                SysNetty sysNetty = entry.getValue();

                // 检查客户端是否已经连接
                if (CommonNetty.ctxMap.get(code) != null) {
                    // 如果已经连接，发送心跳包
                    SendMessage.sendMessage(code, new HeartMessage("256", "999999"));
                } else {
                    // 如果客户端没有连接，检查是否到达重连间隔
                    long currentTime = System.currentTimeMillis();
                    Long lastReconnect = lastReconnectTime.get(code);

                    // 如果没有记录过重连时间，或者上次重连时间距离当前时间超过计算的重连间隔
                    if (lastReconnect == null || (currentTime - lastReconnect > calculateReconnectDelay(code))) {
                        // 更新重连时间
                        lastReconnectTime.put(code, currentTime);
                        // 延时重连
                        retryConnection(sysNetty, code);
                    }
                }
            }
        }
    }

    // 计算重连延迟时间，使用指数回退策略
    public long calculateReconnectDelay(String code) {
        int attempts = reconnectAttempts.getOrDefault(code, 0);
        long delay = Math.min((long) Math.pow(2, attempts) * 5000, MAX_RECONNECT_DELAY * 1000);  // 每次重试时延迟时间逐渐增大，最多延迟60秒
        return delay;
    }

    // 重连方法
    public void retryConnection(SysNetty sysNetty, String code) {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        long delay = calculateReconnectDelay(code);
        scheduler.schedule(() -> {
            log.error(code + " 连接失败，准备重连...");
            new BootNettyClient(sysNetty).run();
            // 更新重连次数
            reconnectAttempts.put(code, reconnectAttempts.getOrDefault(code, 0) + 1);
        }, delay, TimeUnit.MILLISECONDS);  // 延时执行重连
    }
}